package com.landtool.lanbase.netty;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.stream.ChunkedWriteHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;


@Component
public class nettyServer {

    private static final Logger LOGGER = LoggerFactory.getLogger(nettyServer.class);

    @Value("${netty.server.port}")
    public Integer port;

    @Value("${netty.server.portAll}")
    public Integer portAll;


    private void startServer() {
        // 服务端需要2个线程组  boss处理客户端连接  work进行客服端连接之后的处理
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup work = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            ServerBootstrap bootstrap2 = new ServerBootstrap();

            // 服务器 配置
            bootstrap.group(boss, work)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            // HttpServerCodec：将请求和应答消息解码为HTTP消息
                            socketChannel.pipeline().addLast("http-codec", new HttpServerCodec());
                            // HttpObjectAggregator：将HTTP消息的多个部分合成一条完整的HTTP消息
                            socketChannel.pipeline().addLast("aggregator", new HttpObjectAggregator(64*1024));
                            // ChunkedWriteHandler：向客户端发送HTML5文件
                            socketChannel.pipeline().addLast("http-chunked", new ChunkedWriteHandler());
                            // 配置通道处理  来进行业务处理
                            socketChannel.pipeline().addLast(new WebSocketChannelHandler());
                        }
                    })
                    // 使用内存池
                    .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                    // 保持连接数
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    // 保持连接
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            // 绑定端口  开启事件驱动
            LOGGER.info("【服务器启动成功========端口：" + port + "】");

            bootstrap2.group(boss, work)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            // HttpServerCodec：将请求和应答消息解码为HTTP消息
                            socketChannel.pipeline().addLast("http-codec", new HttpServerCodec());
                            // HttpObjectAggregator：将HTTP消息的多个部分合成一条完整的HTTP消息
                            socketChannel.pipeline().addLast("aggregator", new HttpObjectAggregator(64*1024));
                            // ChunkedWriteHandler：向客户端发送HTML5文件
                            socketChannel.pipeline().addLast("http-chunked", new ChunkedWriteHandler());
//                            socketChannel.pipeline().addLast(new WebSocketServerProtocolHandler("/ws"));
                            // 进行设置心跳检测
//                            socketChannel.pipeline().addLast(new IdleStateHandler(60, 30, 60 * 30, TimeUnit.SECONDS));
                            // 配置通道处理  来进行业务处理
                            socketChannel.pipeline().addLast(new WebSocketChannelHandler2());
                        }
                    })
                    // 使用内存池
                    .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                    // 保持连接数
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    // 保持连接
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            // 绑定端口  开启事件驱动
            LOGGER.info("【服务器启动成功========端口：" + portAll + "】");

            Channel channel = bootstrap.bind(port).sync().channel();
            Channel channel2 = bootstrap2.bind(portAll).sync().channel();

            channel2.closeFuture().sync();
            channel.closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            boss.shutdownGracefully();
            work.shutdownGracefully();
        }
    }


    /**
     *  这个注解表示在spring boot依赖注入完成后执行一次该方法，但对方法有很严格的要求
     */
    @PostConstruct()
    public void init() {
        //需要开启一个新的线程来执行netty server 服务器
        new Thread(new Runnable() {
            @Override
            public void run() {
                startServer();
            }
        }).start();

    }



}
